# coding : utf-8
import math
import sympy as sy
import numpy as np
import matplotlib.pyplot as plt
from .misc import clip_angle

def one_bezier_curve(a, b, t):
    """
    @param a: 控制点1
    @param b: 控制点2
    @param t: [0, 1]
    """
    return (1 - t) * a + t * b

def n_bezier_curve(xs, n, k, t):
    """
    @param xs: 控制点序列
    @param n: 贝塞尔曲线阶数
    @param k: 控制点序号
    @param t: [0, 1]
    """
    if n == 1:
        return one_bezier_curve(xs[k], xs[k+1], t)
    else:
        return (1 - t) * n_bezier_curve(xs, n - 1, k, t) + t * n_bezier_curve(xs, n - 1, k + 1, t)

def bezier_curve(xs,ys,num):
    """
    @param xs: 控制点x坐标序列
    @param ys: 控制点y坐标序列
    @param num: 贝塞尔曲线离散点数量(这个地方的理解有错误，因为是递归调用中返回了数值，但勉强可以接受)
    """
    b_xs = []
    b_ys = []
    n = len(xs) - 1
    t_step = 1.0 / (num - 1)
    t = np.arange(0.0,1+t_step,t_step)
    for each in t:
        b_xs.append(n_bezier_curve(xs,n,0,each))
        b_ys.append(n_bezier_curve(ys,n,0,each))
    return zip(b_xs, b_ys)

def GetWaveBezier(x0, y0, dg0, x1, y1, dg1, number):
    """
    @return zip(xx, yy)
    """
    rad0 = math.radians(clip_angle(dg0, 0, 360.0))
    rad1 = math.radians(clip_angle(dg1, 0, 360.0))
    x = sy.Symbol('x')
    y = sy.Symbol('y')
    # distance = math.sqrt((x1-x0)**2 + (y1-y0)**2)
    number = number
    if math.fabs(dg1-dg0) < 1:
        # 计算中点坐标
        xm = (x0 + x1) / 2.0
        ym = (y0 + y1) / 2.0
        # 两给定控制点之间形成的角度
        theta = math.atan2(y1-y0, x1-x0) 
        # 从控制点0旋转到中点需要的角度
        delta = math.degrees(theta - rad0) 
        # 在中点角度上增加一半变化值
        delta = clip_angle(delta, 0, 360.0)
        dgm = math.degrees(theta) + delta / 2.0
        dgm = clip_angle(dgm, 0, 360) 
        # 递归调用
        wave0 = GetWaveBezier(x0, y0, dg0, xm, ym, dgm, int(number/2))
        wave1 = GetWaveBezier(xm, ym, dgm, x1, y1, dg1, number-int(number/2))
        # 拼接结果
        xx0, yy0= zip(*wave0)
        xx1, yy1 = zip(*wave1)
        xx = xx0 + xx1
        yy = yy0 + yy1
        return zip(xx, yy)
    else:
        # 2阶bezier曲线，3个控制点
        k0 = math.tan(rad0)
        k1 = math.tan(rad1)
        # 计算交点
        cp = sy.solve([(y-y0)-k0*(x-x0), (y-y1)-k1*(x-x1)], [x, y])
        # 将原始输入的2个点和交点作为控制点，得到bezier曲线        
        x = [x0, cp[x], x1]
        y = [y0, cp[y], y1]
        return bezier_curve(x, y, number)
